// 日志落地模块的实现
//  抽象基类 派生子类（根据不同落地方向） 使用工厂模式进行创建和分离
#ifndef _M_Sink_H__
#define _M_Sink_H__

#include "util.hpp"
#include <cassert>
#include <fstream>
#include <memory>
#include <sstream>
namespace yhlog
{
    class LogSink
    {
    public:
        using ptr = std::shared_ptr<LogSink>;
        LogSink() {}
        virtual ~LogSink() {}
        virtual void log(const char *data, size_t len) = 0;
    };

    // 落地方向 ：标准输出 指定文件 滚动文件（时间，大小）
    // 标准输出
    class StdoutSink : public LogSink
    {
    public:
        void log(const char *data, size_t len)
        {
            std::cout.write(data, len);
        }
    };
    // 指定文件名
    class FileSink : public LogSink
    {
    public:
        // 构造时传入文件名 并打开文件 将操作句柄管理起来
        FileSink(const std::string &pathname) : _pathname(pathname)
        {
            // 1.创建日志文件所在目录
            util::File::createDirectory(util::File::path(pathname));
            // 2.创建并打开日志文件
            _ofs.open(pathname, std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
        }
        void log(const char *data, size_t len)
        {
            _ofs.write(data, len);
            assert(_ofs.good());
        }

    private:
        std::string _pathname;
        std::ofstream _ofs;
    };
    // 滚动文件
    class RollBySizeSink : public LogSink
    {
    public:
        RollBySizeSink(const std::string &basename, size_t max_size)
            : _basename(basename),
              _max_fsize(max_size),
              _cur_fsize(0),
              _name_count(0)
        {
            std::string pathname = createNewFile();
            // 1.创建日志文件所在目录
            util::File::createDirectory(util::File::path(pathname));
            // 2.创建并打开日志文件
            _ofs.open(pathname, std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
        }

        void log(const char *data, size_t len)
        {
            if (_cur_fsize >= _max_fsize)
            {
                _ofs.close(); // 关闭原来已经打开的文件
                std::string pathname = createNewFile();
                _ofs.open(pathname, std::ios::binary | std::ios::app);
                assert(_ofs.is_open());
                _cur_fsize=0;
            }
            _ofs.write(data, len);
            assert(_ofs.good());
            _cur_fsize+=len;
        }

    private:
        std::string createNewFile() // 进行大小判断
        {
            // 获取系统时间，以时间来构造文件名扩展名
            time_t t = util::Date::now();
            struct tm lt;
            localtime_r(&t, &lt);
            std::stringstream filename;
            filename << _basename;
            filename << lt.tm_year+1900;
            filename << lt.tm_mon+1;
            filename << lt.tm_mday;
            filename << lt.tm_hour;
            filename << lt.tm_min;
            filename << lt.tm_sec;
            filename<<"-";
            filename<<_name_count++;
            filename << ".log";
            return filename.str();
        }

    private:
        size_t _name_count;
        std::string _basename; // 基础文件名 + 扩展时间文件名
        std::ofstream _ofs;
        size_t _max_fsize; // 记录文件最大大小 超过了就要切换文件
        size_t _cur_fsize; // 记录当前文件已经写入的数据大小
    };
    class SinkFactory
    {
    public:
        template <typename SinkType, typename... Args>
        static LogSink::ptr create(Args &&...args)
        {
            return std::make_shared<SinkType>(std::forward<Args>(args)...);
        }
    };
}

#endif
// #ifndef __M_SINK_H__
// #define __M_SINK_H__
// #include "util.hpp"
// #include "message.hpp"
// //#include "formatter.hpp"
// #include <memory>
// #include <mutex>
// #include <sstream>
// #include <fstream>
// namespace yhlog
// {
//     class LogSink
//     {
//     public:
//         using ptr = std::shared_ptr<LogSink>;
//         LogSink() {}
//         virtual ~LogSink() {}
//         virtual void log(const char *data, size_t len) = 0;
//     };
//     class StdoutSink : public LogSink
//     {
//     public:
//         using ptr = std::shared_ptr<StdoutSink>;
//         StdoutSink() = default;
//         void log(const char *data, size_t len)
//         {
//             std::cout.write(data, len);
//         }
//     };
//     class FileSink : public LogSink
//     {
//     public:
//         using ptr = std::shared_ptr<FileSink>;
//         FileSink(const std::string &filename) : _filename(filename)
//         {
//             util::File::createDirectory(util::File::path(filename));
//             _ofs.open(_filename, std::ios::binary | std::ios::app);
//             assert(_ofs.is_open());
//         }
//         const std::string &file() { return _filename; }
//         void log(const char *data, size_t len)
//         {
//             _ofs.write((const char *)data, len);
//             if (_ofs.good() == false)
//             {
//                 std::cout << "日志输出文件失败！\n";
//             }
//         }

//     private:
//         std::string _filename;
//         std::ofstream _ofs;
//     };
//     class RollSink : public LogSink
//     {
//     public:
//         using ptr = std::shared_ptr<RollSink>;
//         RollSink(const std::string &basename, size_t max_fsize) : _basename(basename), _max_fsize(max_fsize), _cur_fsize(0)
//         {
//             util::File::createDirectory(util::File::path(basename));
//         }
//         void log(const char *data, size_t len)
//         {
//             initLogFile();
//             _ofs.write(data, len);
//             if (_ofs.good() == false)
//             {
//                 std::cout << "日志输出文件失败！\n";
//             }
//             _cur_fsize += len;
//         }

//     private:
//         void initLogFile()
//         {
//             if (_ofs.is_open() == false || _cur_fsize >= _max_fsize)
//             {
//                 _ofs.close();
//                 std::string name = createFilename();
//                 _ofs.open(name, std::ios::binary | std::ios::app);
//                 assert(_ofs.is_open());
//                 _cur_fsize = 0;
//                 return;
//             }
//             return;
//         }
//         std::string createFilename()
//         {
//             time_t t = time(NULL);
//             struct tm lt;
//             localtime_r(&t, &lt);
//             std::stringstream ss;
//             ss << _basename;
//             ss << lt.tm_year + 1900;
//             ss << lt.tm_mon + 1;
//             ss << lt.tm_mday;
//             ss << lt.tm_hour;
//             ss << lt.tm_min;
//             ss << lt.tm_sec;
//             ss << ".log";
//             return ss.str();
//         }

//     private:
//         std::string _basename;
//         std::ofstream _ofs;
//         size_t _max_fsize;
//         size_t _cur_fsize;
//     };

//     class SinkFactory
//     {
//     public:
//         template <typename SinkType, typename... Args>
//         static LogSink::ptr create(Args &&...args)
//         {
//             return std::make_shared<SinkType>(std::forward<Args>(args)...);
//         }
//     };

// }
// #endif